package myplay

import (
	"ginplay/myproxy"
	"ginplay/mytool"

	"encoding/json"
	"fmt"
	"net/http"
	"os"
	"os/exec"

	"github.com/gin-gonic/gin"
)

type GETPAGEREQUEST struct {
	Pagenow  int    `json:"pagenow"`
	Pagesize int    `json:"pagesize"`
	Search   string `json:"search"`
}

type PLAYBOOKS struct {
	Id       int    `json:"id"`
	Name     string `json:"name"`
	Hosts    string `json:"hosts"`
	Playbook string `json:"playbook"`
	Forks    string `json:"forks"`
	Key      string `json:"key"`
	Proxy    string `json:"proxy"`
}

func getContent(onegetrequest GETPAGEREQUEST) []PLAYBOOKS {
	tsql := "select id,name,hosts,playbook,forks,key,proxy from myplay where name like ? limit ?,?"
	rows := mytool.SelectByPara(tsql, "%"+onegetrequest.Search+"%", (onegetrequest.Pagenow-1)*onegetrequest.Pagesize, onegetrequest.Pagesize)
	defer rows.Close()
	var myplaybook []PLAYBOOKS
	for rows.Next() {
		var oneplay PLAYBOOKS
		rows.Scan(&oneplay.Id, &oneplay.Name, &oneplay.Hosts, &oneplay.Playbook, &oneplay.Forks, &oneplay.Key, &oneplay.Proxy)
		myplaybook = append(myplaybook, oneplay)
	}
	return myplaybook
}

func getAllCount(onegetrequest GETPAGEREQUEST) string {
	tsql := "select count(1) as allcount from myplay where name like ?"
	rows := mytool.SelectByPara(tsql, "%"+onegetrequest.Search+"%")
	defer rows.Close()
	var allcount string
	for rows.Next() {
		rows.Scan(&allcount)
	}
	return allcount
}

type RETURNRESULT struct {
	Result   []PLAYBOOKS `json:"result"`
	Allcount string      `json:"allcount"`
}

func GetByPage(c *gin.Context) {
	var onegetrequest GETPAGEREQUEST
	if err := c.BindJSON(&onegetrequest); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}
	fmt.Println(onegetrequest)
	myplaybook := getContent(onegetrequest)
	allcount := getAllCount(onegetrequest)
	var returnresult RETURNRESULT
	returnresult.Allcount = allcount
	returnresult.Result = myplaybook
	jsonData, _ := json.Marshal(returnresult)
	fmt.Println(string(jsonData))
	c.String(http.StatusOK, string(jsonData))
}

func Realadd(c *gin.Context) {
	var oneplay PLAYBOOKS
	if err := c.BindJSON(&oneplay); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}
	tsql := "insert into myplay (name,hosts,playbook,forks,key,proxy) VALUES( ?,?,?,?,?,? )"
	mytool.UpdateByPara(tsql, oneplay.Name, oneplay.Hosts, oneplay.Playbook, oneplay.Forks, oneplay.Key, oneplay.Proxy)
	c.String(http.StatusOK, string("添加成功"))
}

func Multidelete(c *gin.Context) {
	var multiids []int
	c.BindJSON(&multiids)
	fmt.Println(multiids)

	for _, value := range multiids {
		tsql := "delete from myplay where id = ?"
		mytool.UpdateByPara(tsql, value)
	}
	c.String(http.StatusOK, string("批量删除成功"))
}

func GetContentByID(id string) PLAYBOOKS {
	tsql := "select id,name,hosts,playbook,forks,key,proxy from myplay where id = ?"
	rows := mytool.SelectByPara(tsql, id)
	defer rows.Close()
	var oneplay PLAYBOOKS
	for rows.Next() {
		rows.Scan(&oneplay.Id, &oneplay.Name, &oneplay.Hosts, &oneplay.Playbook, &oneplay.Forks,
			&oneplay.Key, &oneplay.Proxy)
	}
	return oneplay
}

func GetById(c *gin.Context) {
	id := c.Query("id")
	oneplay := GetContentByID(id)
	jsonData, _ := json.Marshal(oneplay)
	c.String(http.StatusOK, string(jsonData))
}

func Update(c *gin.Context) {
	var oneplay PLAYBOOKS
	c.BindJSON(&oneplay)
	tsql := "replace into myplay (id, name,hosts,playbook,forks,key,proxy) VALUES(?,?,?,?,?,?,?)"
	mytool.UpdateByPara(tsql, oneplay.Id, oneplay.Name, oneplay.Hosts, oneplay.Playbook, oneplay.Forks,
		oneplay.Key, oneplay.Proxy)
	c.String(http.StatusOK, string("更新成功"))
}

func DeleteById(c *gin.Context) {
	id := c.Query("id")
	tsql := "delete from myplay where id = ?"
	mytool.UpdateByPara(tsql, id)
	c.String(http.StatusOK, string("删除成功"))
}

func CopyById(c *gin.Context) {
	id := c.Query("id")
	tsql := `insert into myplay (name,hosts,playbook,forks,key,proxy) select ?,hosts,playbook,forks,key,proxy 
	from myplay where id = ?`
	mytool.UpdateByPara(tsql, "bycopyfrom-id"+id, id)
	c.String(http.StatusOK, string("复制成功"))
}

func writeStrTofile(filepath string, writecontent string) {
	file, _ := os.Create(filepath)
	defer file.Close()
	file.Write([]byte(writecontent))
}

func runcommandBack(oneplay PLAYBOOKS) string {
	inifile := fmt.Sprintf("/tmp/%d.ini", oneplay.Id)
	ymlfile := fmt.Sprintf("/tmp/%d.yml", oneplay.Id)
	logfile := fmt.Sprintf("/tmp/%d.log", oneplay.Id)
	writeStrTofile(inifile, oneplay.Hosts)
	writeStrTofile(ymlfile, oneplay.Playbook)
	var command string
	if oneplay.Proxy == "false" {
		command = fmt.Sprintf("ansible-playbook --flush-cache --private-key %s -i %s %s -f %s 2>&1 | tee %s", oneplay.Key, inifile, ymlfile, oneplay.Forks, logfile)
	} else {
		proxyinfo := myproxy.GetByName(oneplay.Proxy)
		command = fmt.Sprintf("ansible-playbook --flush-cache --ssh-common-args '-o ProxyCommand=\"ssh -i %s -W %%h:%%p -p 22 -q %s@%s\"' --private-key %s -i %s %s -f %s 2>&1 | tee %s",
			proxyinfo.Key, proxyinfo.User, proxyinfo.Address, oneplay.Key, inifile, ymlfile, oneplay.Forks, logfile)
	}
	fmt.Println(command)
	myresult := exec.Command("sh", "-c", command)
	out, err := myresult.Output()
	if err != nil {
		fmt.Println(err)
	}
	file, _ := os.OpenFile(logfile, os.O_APPEND|os.O_WRONLY, 0644)
	defer file.Close()
	file.WriteString("ENDENDEND")
	return string(out)
}

func RunById(c *gin.Context) {
	id := c.Query("id")
	oneplay := GetContentByID(id)
	go runcommandBack(oneplay)
	c.String(http.StatusOK, fmt.Sprintf("%d", oneplay.Id))
}

func Getlog(c *gin.Context) {
	id := c.Query("id")
	content, _ := os.ReadFile(fmt.Sprintf("/tmp/%s.log", id))
	c.String(http.StatusOK, string(content))
}

func CheckTable() {
	tsql := `select name from sqlite_master where name="myplay"`
	rows := mytool.SelectNoPara(tsql)
	defer rows.Close()
	if rows.Next() {
		fmt.Println("myplay is exits")
	} else {
		fmt.Println("create myplay")
		csql := `
CREATE TABLE myplay (
  id INTEGER PRIMARY KEY,
  name varchar(200) DEFAULT '',
  hosts text DEFAULT '',
  playbook text DEFAULT '',
  forks varchar(50) DEFAULT '',
  key varchar(50) DEFAULT '',
  proxy varchar(50) default 'false'
);
        `
		mytool.UpdateNoPara(csql)
	}
}
